home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- #include <ctype.h>
- #include <std.h>
-
- /* the next 6 #defines implement a very fast in-line stack abstraction */
-
- #define MAX_STACK_SIZE 32
- #define DISPOSE_STACK(S) (free(S))
- #define PUSH(LOW,HIGH) do {top->lo = LOW;top++->hi = HIGH;} while (0)
- #define POP(LOW,HIGH) do {LOW = (--top)->lo;HIGH = top->hi;} while (0)
- #define STACK_NOT_EMPTY (stack < top)
- #define SWAP(A,B) do {char *_temp = (A);(A) = (B);(B) = _temp;} while (0)
-
- /* Discontinue quicksort algorithm when partition gets below this size.
- This particular magic number was chosen to work best on a Sun 4/260. */
- #define MAX_THRESH 30
-
- /* Data structure for stack of unfulfilled obligations. */
- typedef struct
- {
- char **lo;
- char **hi;
- } stack_node;
-
- /* Once main array is partially sorted by quicksort the remainder is
- completely sorted using insertion sort, since this is efficient
- for partitions below MAX_THRESH size. BASE points to the beginning
- of the array to sort, and END_PTR points at the very last element in
- the array (*not* one beyond it!). */
-
- inline static void
- insert_sort (char **base_ptr, char **end_ptr)
- {
- char **run_ptr;
- char **tmp_ptr = base_ptr;
- #ifdef __GNUC__
- char **thresh = end_ptr <? base_ptr + MAX_THRESH;
- #else
- char **thresh = base_ptr + MAX_THRESH;
- if (thresh > end_ptr)
- thresh = end_ptr;
- #endif
-
- /* Find the smallest element in the first threshold and put it at the
- end of the array. This is guaranteed to be the smallest element in
- the array, and it speeds up the inner loop of insertion sort. */
-
- for (run_ptr = tmp_ptr + 1; run_ptr <= thresh; run_ptr++)
- if (strcmp (*run_ptr, *tmp_ptr) < 0)
- tmp_ptr = run_ptr;
-
- SWAP (*tmp_ptr, *base_ptr);
-
- /* Typical insertion sort, but we run from the `right-hand-side'
- downto the `left-hand-side.' */
-
- for (run_ptr = base_ptr + 1; run_ptr < end_ptr; run_ptr++)
- {
- char *temp = *(tmp_ptr = run_ptr + 1);
-
- /* Select the correct location for the new element,
- by sliding everyone down by 1 to make room! */
-
- while (strcmp (temp, *--tmp_ptr) < 0)
- tmp_ptr[1] = *tmp_ptr;
-
- tmp_ptr[1] = temp;
- }
- }
-
- /* Return the median value selected from among the
- LOW, MIDDLE, and HIGH. Rearrange LOW and HIGH so
- the three values are sorted amongst themselves.
- This speeds up later work... */
-
- inline static char *
- find_pivot (char **low, char **high)
- {
- char **middle = low + ((high - low ) >> 1);
-
- if (strcmp (*middle, *low) < 0)
- SWAP (*middle, *low);
- if (strcmp (*high, *middle) < 0)
- SWAP (*middle, *high);
- else
- return *middle;
-
- if (strcmp (*middle, *low) < 0)
- SWAP (*middle, *low);
-
- return *middle;
- }
-
- /* Order elements using quicksort. This implementation incorporates
- 4 optimizations discussed in Sedgewick:
-
- 1. Non-recursive, using an explicit stack of log (n) pointers that
- indicate the next array partition to sort.
-
- 2. Choses the pivot element to be the median-of-three, reducing
- the probability of selecting a bad pivot value.
-
- 3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving
- insertion sort to sort within the partitions. This is a
- big win, since insertion sort is faster for small, mostly
- sorted array segements.
-
- 4. The larger of the 2 sub-partitions are always pushed onto the
- stack first, with the algorithm then concentrating on the
- smaller partition. This *guarantees* no more than log (n)
- stack size is needed! */
-
- void
- sort (char **base_ptr, int total_elems)
- {
- if (total_elems > MAX_THRESH)
- {
- char **lo = base_ptr;
- char **hi = lo + (total_elems - 1);
- char **left_ptr;
- char **right_ptr;
- stack_node stack[MAX_STACK_SIZE];
- stack_node *top = stack + 1;
-
- while (STACK_NOT_EMPTY)
- {
- /* Select the median-of-three here. This allows us to
- skip forward for the LEFT_PTR and RIGHT_PTR. */
- char *pivot = find_pivot (lo, hi);
- left_ptr = lo + 1;
- right_ptr = hi - 1;
-
- /* Here's the famous ``collapse the walls'' section of
- quicksort. Gotta like those tight inner loops! */
- do
- {
- while (strcmp (*left_ptr, pivot) < 0)
- left_ptr++;
-
- while (strcmp (pivot, *right_ptr) < 0)
- right_ptr--;
-
- if (left_ptr < right_ptr)
- {
- SWAP (*left_ptr, *right_ptr);
- left_ptr++;
- right_ptr--;
- }
- else if (left_ptr == right_ptr)
- {
- left_ptr++;
- right_ptr--;
- break;
- }
- }
- while (left_ptr <= right_ptr);
-
- if ((right_ptr - lo) <= MAX_THRESH)
- {
- if ((hi - left_ptr) <= MAX_THRESH) /* ignore both small tables */
- POP (lo, hi);
- else /* ignore small left table */
- lo = left_ptr;
- }
- else if ((hi - left_ptr) <= MAX_THRESH) /* ignore small right table */
- hi = right_ptr;
- else if ((right_ptr - lo) > (hi - left_ptr))
- { /* push larger left table */
- PUSH (lo, right_ptr);
- lo = left_ptr;
- }
- else
- { /* push larger right table */
- PUSH (left_ptr, hi);
- hi = right_ptr;
- }
- }
- }
-
- insert_sort (base_ptr, base_ptr + (total_elems - 1));
- }
-